﻿namespace Neovolve.Toolkit.Reflection
{
    using System;
    using System.Diagnostics;
    using System.Text;

    /// <summary>
    /// The <see cref="MethodCacheKey"/>
    ///   struct is used to describe a method for referencing method information in a cache.
    /// </summary>
    internal struct MethodCacheKey
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MethodCacheKey"/> struct.
        /// </summary>
        /// <param name="declaringType">
        /// Type of the declaring.
        /// </param>
        /// <param name="methodName">
        /// Name of the method.
        /// </param>
        /// <param name="parameterTypes">
        /// The parameter types.
        /// </param>
        public MethodCacheKey(Type declaringType, String methodName, params Type[] parameterTypes)
            : this()
        {
            DeclaringType = declaringType;
            MethodName = methodName;
            ParameterTypes = parameterTypes;
        }

        /// <summary>
        /// Returns a description of the method signature.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> containing a description of the method signature.
        /// </returns>
        public override String ToString()
        {
            Debug.Assert(DeclaringType != null, "No declaring type has been provided");
            Debug.Assert(String.IsNullOrEmpty(MethodName) == false, "No method name has been provided");

            String declaringTypeName = DeclaringType.Name;
            String methodName = MethodName;
            StringBuilder builder = new StringBuilder(declaringTypeName);

            builder.Append(".");
            builder.Append(methodName);
            builder.Append("(");

            if (ParameterTypes != null)
            {
                for (Int32 index = 0; index < ParameterTypes.Length; index++)
                {
                    Type parameterType = ParameterTypes[index];

                    if (index > 0)
                    {
                        builder.Append(", ");
                    }

                    Debug.Assert(parameterType != null, "Null parameter type encountered");

                    builder.Append(parameterType.Name);
                }
            }

            builder.Append(")");

            return builder.ToString();
        }

        /// <summary>
        /// Gets or sets the type of the declaring.
        /// </summary>
        /// <value>
        /// The type of the declaring.
        /// </value>
        public Type DeclaringType
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the name of the method.
        /// </summary>
        /// <value>
        /// The name of the method.
        /// </value>
        public String MethodName
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the parameter types.
        /// </summary>
        /// <value>
        /// The parameter types.
        /// </value>
        public Type[] ParameterTypes
        {
            get;
            set;
        }
    }
}